/*
    IntersectAlignments.cpp

    Copyright (C) 2012 Leonardo Boquillon and Daniel Gutson, FuDePAN

    This file is part of Biorinox.

    Biorinox is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Biorinox is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <set>
#include <algorithm>

#include "mili/mili.h"
#include "biopp/biopp.h"

#include "IntersectAlignments.h"
#include "exception.h"

IntersectAlignments::IntersectAlignments(const std::string& ft1, const std::string& ft2, const std::string& op1, const std::string& op2, const std::string& pf1, const std::string& pf2)
    : inputFasta1(ft1),
      inputFasta2(ft2),
      outputFasta1(op1),
      outputFasta2(op2),
      prefix1(pf1),
      prefix2(pf2)
{
}

void IntersectAlignments::run()
{

    std::set<std::string> intersectionSet;
    std::set<std::string> fastaNames1;
    std::set<std::string> fastaNames2;

    IntersectAlignments::loadNames(inputFasta1, fastaNames1, prefix1);
    IntersectAlignments::loadNames(inputFasta2, fastaNames2, prefix2);

    set_intersection(fastaNames1.begin(), fastaNames1.end(), fastaNames2.begin(), fastaNames2.end(), std::inserter(intersectionSet, intersectionSet.begin()));

    IntersectAlignments::saveIntersection(inputFasta1, outputFasta1, intersectionSet, prefix1);
    IntersectAlignments::saveIntersection(inputFasta2, outputFasta2, intersectionSet, prefix2);
}

std::string IntersectAlignments::removePrefix(std::string fullName, const std::string& prefix)
{
    if (!prefix.empty() && mili::begins_with(mili::lstring(fullName), mili::lstring(prefix)))
    {
        fullName.erase(0, prefix.size());
    }

    return fullName;
}

void IntersectAlignments::loadNames(const std::string& fileName, std::set<std::string>& setSequence, const std::string& prefix)
{

    bioppFiler::FastaParser<Sequence> fp(fileName);
    Sequence seq;
    std::string name;

    try
    {
        while (fp.getNextSequence(name, seq))
            mili::insert_into(setSequence, IntersectAlignments::removePrefix(name, prefix));
    }
    catch (const biopp::MethodNotImplemented& e)
    {
        throw InvalidSequence(name + " " + fileName);
    }
}

void IntersectAlignments::saveIntersection(const std::string& fastaInput, const std::string& fastaOutput, std::set<string> & intersectionSet, const std::string& prefix)
{
    bioppFiler::FastaParser<Sequence> fp(fastaInput);
    bioppFiler::FastaSaver<Sequence> fs(fastaOutput);

    Sequence seq;
    std::string name;

    while (fp.getNextSequence(name, seq))
    {
        if (mili::contains(intersectionSet, IntersectAlignments::removePrefix(name, prefix)))
        {
            fs.saveNextSequence(name, seq);
        }
    }
}
